package org.xx.armory.rpc.decorators;

import org.xx.armory.bindings.BoundParamCollection;
import org.xx.armory.commons.AbstractLifeCycle;
import org.xx.armory.rpc.Decorator;
import org.xx.armory.service.Invocation;
import org.xx.armory.service.ServiceContext;

/**
 * 修饰器的基本实现。
 */
public abstract class AbstractDecorator
        extends AbstractLifeCycle
        implements Decorator {
    /**
     * {@inheritDoc}
     */
    @Override
    public Object execute(
            Invocation invocation,
            BoundParamCollection params,
            ServiceContext serviceContext
    )
            throws Throwable {
        before(invocation, params, serviceContext);

        try {
            final Object ret = invocation.execute(params, serviceContext);
            return done(invocation, params, serviceContext, ret);
        } finally {
            always(invocation, params, serviceContext);
        }
    }

    /**
     * 在执行指定的方法之前执行准备工作。
     * <p>如果此方法抛出异常，那么不会执行指定的方法。{@link #done(Invocation, BoundParamCollection, ServiceContext, Object)}和{@link #always(Invocation, BoundParamCollection, ServiceContext)}方法也不会被执行。</p>
     *
     * @param invocation
     *         用于实现链式调用的执行器。
     * @param params
     *         执行方法的参数集合，修改此集合的内容可以修改最终执行的方法的参数。
     * @param serviceContext
     *         服务上下文。
     * @throws Exception
     *         如果执行准备工作出现错误。
     */
    protected void before(
            Invocation invocation,
            BoundParamCollection params,
            ServiceContext serviceContext
    )
            throws Exception {

    }

    /**
     * 执行指定的方法成功之后执行，用于成功后的清理工作，或者修改返回值。
     * <p>只有指定方法执行成功后才会被执行。</p>
     *
     * @param invocation
     *         用于实现链式调用的执行器。
     * @param params
     *         执行方法的参数集合，修改此集合的内容可以修改最终执行的方法的参数。
     * @param serviceContext
     *         服务上下文。
     * @param result
     *         执行方法的返回值。
     * @return 修改后的返回值。
     * @throws Exception
     *         如果执行清理工作或者修改返回值出错。
     */
    protected Object done(
            Invocation invocation,
            BoundParamCollection params,
            ServiceContext serviceContext,
            Object result
    )
            throws Exception {
        return result;
    }

    /**
     * 执行指定的方法后执行，用于清理工作。
     * <p>即时指定的方法抛出异常或者{@link #done(Invocation, BoundParamCollection, ServiceContext, Object)}方法抛出异常，此方法也会被执行。</p>
     * <p>如果此方法抛出异常，会掩盖指定方法或者{@link #done(Invocation, BoundParamCollection, ServiceContext, Object)}方法抛出的异常。</p>
     *
     * @param invocation
     *         用于实现链式调用的执行器。
     * @param params
     *         执行方法的参数集合，修改此集合的内容可以修改最终执行的方法的参数。
     * @param serviceContext
     *         服务上下文。
     * @throws Exception
     *         如果执行清理工作出错。
     */
    protected void always(
            Invocation invocation,
            BoundParamCollection params,
            ServiceContext serviceContext
    )
            throws Exception {

    }
}
